-- local skynet = require "skynet"
-- require "skynet.manager"    -- import skynet.register
-- local db = {}
-- local command = {}
-- function command.GET(key) --在方法集合中添加指令 
--     return db[key]
-- end
-- function command.SET(key, value)
--     db[key] = value
-- end
-- skynet.start(function()
--     --注册该服务的lua消息回调函数
--     skynet.dispatch("lua", function(session, address, cmd, ...)
--         --接受到的第一参数作为命令使用
--         cmd = cmd:upper()  
--         local f = command[cmd] --查询cmd命令的具体处理方法
--         if f then
--             --执行查询到的方法，并且通过skynet.ret将执行结果返回
--             skynet.retpack(f(...))
--         else
--             skynet.error(string.format("Unknown command %s", tostring(cmd)))
--         end
--     end)
--     skynet.register ".mydb"  --给当前服务注册一个名字，便于其他服务给当前服务发送消息
-- end)


-- -- 服务重入问题
-- local skynet = require "skynet"
-- require "skynet.manager"    -- import skynet.register
-- local db = {}

-- local command = {}

-- function command.GET(key)
--     skynet.sleep(1000)      --这里加了一个阻塞函数
--     return db[key]
-- end

-- function command.SET(key, value)
--     db[key] = value
-- end

-- skynet.start(function()
--     skynet.dispatch("lua", function(session, address, cmd, ...)
--         cmd = cmd:upper()  
--         local f = command[cmd] 
--         if f then
--             skynet.retpack(f(...))
--         else
--             skynet.error(string.format("Unknown command %s", tostring(cmd)))
--         end
--     end)
--     skynet.register ".mydb" 
-- end)


-- 上面出现的情况，就是因为，mydb服务处理上一个请求还没结束时，又来了一个新的请求，
-- 并且新的请求改变的mydb中name的值，所以等到第一个请求从阻塞状态恢复时，获取的到值也变了。
-- ​上面的例子即使把skynet.sleep去掉，只要请求发送足够频繁，依然存在重入的问题


local skynet = require "skynet"
require "skynet.manager"    -- import skynet.register
local queue = require "skynet.queue"
local cs = queue()  --获取一个执行队列

local db = {}
local command = {}

function command.GET(key)
    skynet.sleep(1000)      --这里加了一个阻塞函数
    return db[key]
end

function command.SET(key, value)
    db[key] = value
end

skynet.start(function()
    skynet.dispatch("lua", function(session, address, cmd, ...)
        cmd = cmd:upper()  
        local f = command[cmd] 
        if f then
            --将f丢到队列中去执行，队列中的函数严格按照先后顺序进行执行
            skynet.retpack(cs(f, ...))  
        else
            skynet.error(string.format("Unknown command %s", tostring(cmd)))
        end
    end)
    skynet.register ".mydb" 
end)


-- ​ 上面的输出结果就是我们想要的了，把所有不希望重入的函数丢到cs队列中去执行，队列将依次执行每一个函数，前一个函数还没执行完的时候，后面的函数永远不会被执行。

-- ​ 执行队列虽然解决了重入的问题，但是明显降低了服务的并发处理能力，所以使用执行队列的时候尽量缩小临界区的颗粒度大小。